package main

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"publish/pod"

	"github.com/fatih/color"
	"github.com/gookit/config/v2"
	"github.com/gookit/config/v2/yaml"
	"github.com/manifoldco/promptui"
	"github.com/urfave/cli/v2"
)

var (
	repoConfig *pod.Repo
)

const (
	GlobeConfig = "/usr/local/etc/cinema8150/publish/config.yml"
	RepoKey     = "defaultRepo"
)

func main() {

	var develop bool
	var verbose bool
	var release bool
	var mode string
	var version string

	config.WithOptions(func(o *config.Options) {
		o.DumpFormat = config.Yaml
	})
	config.AddDriver(yaml.Driver)
	err := config.LoadFiles(GlobeConfig)
	if err != nil {
		// panic(err)
	}

	repoConfig = &pod.Repo{}
	err = config.BindStruct(RepoKey, repoConfig)
	if err != nil {
		// panic(err)
	}

	app := &cli.App{
		Name:  "publish",
		Usage: "Help you backup and replace your blog's images.",
		Flags: []cli.Flag{
			&cli.StringFlag{
				Name:        "type",
				Usage:       "Set update type for this publish other than custom version. eg: \"publish -t feature | publish -t f\"",
				Aliases:     []string{"t"},
				Destination: &mode,
			},
			&cli.BoolFlag{
				Name:        "develop",
				Usage:       "Publish develop version, default update rule is: x.y.z-beta.n+1",
				Aliases:     []string{"d"},
				Required:    false,
				Destination: &develop,
			},
			&cli.BoolFlag{
				Name:        "release",
				Usage:       "Publish release version, default update rule is: x.y.z-beta.n -> x.y.x",
				Aliases:     []string{"r"},
				Required:    false,
				Destination: &release,
			},
			&cli.StringFlag{
				Name:        "version",
				Usage:       "Set custom version for this publish without default rule. eg: \"publish -v 11.2.0\"",
				Aliases:     []string{"v"},
				Destination: &version,
			},
			&cli.BoolFlag{
				Name:        "verbose",
				Usage:       "Show more debugging information",
				Required:    false,
				Destination: &verbose,
			},
		},
		Action: func(c *cli.Context) error {
			// select repo which will be published to.
			repo, err := selectPublishRepo()
			if err != nil {
				color.Red(err.Error())
				return nil
			}

			// sync pod repo
			err = pod.SyncProject(repo.Path)
			if err != nil {
				color.Red(err.Error())
				return nil
			}

			// sync current project
			path, err := os.Getwd()
			if err != nil {
				color.Red(err.Error())
				return nil
			}
			err = pod.SyncProject(path)
			if err != nil {
				color.Red(err.Error())
				return nil
			}

			if len(version) > 0 {
				err := pod.UpdateVersion(version, develop, repo)
				if err != nil {
					color.Red(err.Error())
				}
				return nil
			}

			if release {
				develop = false
			}

			currentMode := pod.Update_Default
			if len(mode) > 0 {
				switch mode {
				case "f", "feature":
					currentMode = pod.Update_Feature
				case "b", "bugfix":
					currentMode = pod.Update_Bugfix
				case "r", "refactor":
					currentMode = pod.Update_Refactor
				default:
					typeHelpTips()
					return nil
				}
			}

			err = pod.UpdateVersionByRule(currentMode, develop, repo)
			if err != nil {
				color.Red(err.Error())
			}
			return nil
		},
	}
	if err := app.Run(os.Args); err != nil {
		log.Fatal(err)
	}
}

func selectPublishRepo() (*pod.Repo, error) {
	if len(repoConfig.Path) == 0 {
		repos, err := pod.RepoList()
		if err != nil {
			panic(err)
		}
		var items = []string{}
		for _, v := range repos {
			items = append(items, v.Name+" : "+v.URL)
		}

		prompt := promptui.Select{
			Label: "Select repo for this version which will be published to",
			Items: items,
		}
		index, _, err := prompt.Run()

		if err != nil {
			fmt.Printf("Prompt failed %v\n", err)
			panic(err)
		}

		selectRepo := repos[index]
		prompt = promptui.Select{
			Label: fmt.Sprintf("Select \"%s\" for this publish, would you set it as default publish repo", selectRepo.Name),
			Items: []string{
				"none : you will chose repo for every publish",
				fmt.Sprintf("globe : use \"%s\" as default publish repo", selectRepo.Name),
				// fmt.Sprintf("current : use \"%s\" as default publish repo for current project", selectRepo.Name),
			},
		}
		index, _, err = prompt.Run()
		if err != nil {
			fmt.Printf("Prompt failed %v\n", err)
			panic(err)
		}
		switch index {
		case 1:
			repoConfig = selectRepo
			config.Set(RepoKey, repoConfig, false)
		}

		exsist := isExist(GlobeConfig)
		if !exsist {
			//递归创建文件夹
			err := os.MkdirAll(filepath.Dir(GlobeConfig), os.ModePerm)
			if err != nil {
				fmt.Println(err)
				return nil, err
			}
		}

		fileWriter, err := os.Create(GlobeConfig)
		if err != nil {
			return nil, err
		}
		defer fileWriter.Close()
		_, err = config.DumpTo(fileWriter, config.Yaml)
		if err != nil {
			fmt.Println(err)
		}
	}
	return repoConfig, nil
}

func isExist(path string) bool {
	_, err := os.Stat(path)
	if err != nil {
		if os.IsExist(err) {
			return true
		}
		if os.IsNotExist(err) {
			return false
		}
		fmt.Println(err)
		return false
	}
	return true
}

func typeHelpTips() {
	println(
		`
NAME:
publish - Help you backup and replace your blog's images.

USAGE:
publish -t [argument]

COMMANDS:
help, h  Shows a list of commands or help for one command

LEGAL ARGUMENT:
refactor, r, x         Publish refactor version, update rule is: x+1.y.z
feature, f, y          Publish feature version, update rule is: x.y+1.z
bugfix, b, z           Publish bugfix version, update rule is: x.y.z+1
--help, -h                 show help (default: false)
`)
}
